#ifndef _PLANE_H_
#define _PLANE_H_

#include "../cuCommon/cuTypes.h"

struct SPlane
{
  float3 abc;
  float d;
};

SDH_CALL
SPlane * Plane(SPlane *pPlane, const float3 & n, float dist = 0.0f)
{
  float nlength = length(n);
  pPlane->abc = n / nlength;
  pPlane->d = dist / nlength;

  return pPlane;
}

SDH_CALL
SPlane * Plane(SPlane *pPlane, float nx, float ny, float nz, float dist = 0.0f)
{
  float3 normal = {nx, ny, nz};
  float nlength = length(normal);

  pPlane->abc = normal / nlength;
  pPlane->d = dist / nlength;

  return pPlane;
}

SDH_CALL
SPlane * Plane(SPlane *pPlane, const float3 & n, const float3 & p)
{
  pPlane->abc = normalize(n);
  pPlane->d = -dot(pPlane->abc, p);

  return pPlane;
}

SDH_CALL
SPlane * Plane(SPlane *pPlane, const float3 & p1, const float3 & p2, const float3 & p3)
{
  pPlane->abc = normalize(cross(p2-p1, p3-p1));
  pPlane->d = -dot(pPlane->abc, p1);

  return pPlane;
}

SDH_CALL
SPlane * Plane(SPlane *pPlane, const float4 & p1, const float4 & p2, const float4 & p3)
{
  pPlane->abc = normalize(cross(xyz(p2)-xyz(p1), xyz(p3)-xyz(p1)));
  pPlane->d = -dot(pPlane->abc, p1);

  return pPlane;
}

SDH_CALL
float SignedDistanceToPoint(const SPlane & plane, const float3 & p)
{
  return dot(plane.abc, p) + plane.d;
}

SDH_CALL
float SignedDistanceToPoint(const SPlane & plane, const float3 & p, float3 & cp)
{
  float dist = SignedDistanceToPoint(plane, p);
  cp = p - dist * plane.abc;
  
  return dist;
}

SDH_CALL
float DistanceToPoint(const SPlane & plane, const float3 & p)
{
  return abs(dot(plane.abc, p) + plane.d);
}

SDH_CALL
float3 Point(const SPlane & plane)
{
  return (-plane.d) * plane.abc;
}

SDH_CALL
int HemiSpace(const SPlane & plane, const float3 & p)
{
  return sign(SignedDistanceToPoint(plane, p));
}

#endif // _PLANE_H_